"""
This file is part of GSBEdit. For copyright and licensing information, please
see gsbedit.py in the GSBEdit base directory.
"""


import wx
import copy
import sys


MT_SHOW_ALL = 2000
MT_TREE = 2001


class ModuleTree(wx.Panel):
    def __init__(self, parent, gsbi, select_callback, double_select_callback):
        wx.Panel.__init__(self, parent, -1)
        
        self.gsbi = gsbi
        self.select_callback = select_callback
        self.double_select_callback = double_select_callback

        # Defaults are to show only modules from the selected mod, and there
        # is no selected module.
        self.show_all = False
        self.module_data = None

        # The only two widgets we need are a checkbox to show all modules, and
        # the module tree itself.
        show_all_modules = wx.CheckBox(self, MT_SHOW_ALL, 'Show all modules')
        self.module_tree = wx.TreeCtrl(self, MT_TREE, style = wx.TR_HIDE_ROOT | wx.TR_HAS_BUTTONS | wx.TR_LINES_AT_ROOT | wx.BORDER_SUNKEN)
        
        top_bar = wx.BoxSizer(wx.HORIZONTAL)
        top_bar.Add(show_all_modules, 0, wx.EXPAND)
        
        content = wx.BoxSizer(wx.VERTICAL)
        content.Add(top_bar, 0, wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT, border=10)
        content.Add(self.module_tree, 1, wx.EXPAND | wx.ALL, border=10)
        
        self.SetSizer(content)
        
        self.Bind(wx.EVT_CHECKBOX, self.update_show_all, id=MT_SHOW_ALL)
        self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.edit_module, id=MT_TREE)
        self.Bind(wx.EVT_TREE_SEL_CHANGED, self.select_module, id=MT_TREE)
        
        # Populate the tree with the relevant modules
        self.refresh_tree()
        
    
    def generate_tree_data(self, tree_data, mod):
        mod_name = mod.get_friendly_name()
        all_modules = mod.get_module_list()
        
        tree_data[mod_name] = {}
        for race,modules in all_modules.iteritems():
            tree_data[mod_name][race] = {}
            for module,module_obj in modules.iteritems():
                if module_obj.get_internal_name() == 'tactical':
                    continue
            
                try:
                    size = module_obj.get_value('config', 'size').title()
                except:
                    size = 'Unknown'
                mtype = module_obj.get_value('config', 'category').title()
                
                if not(size in tree_data[mod_name][race]):
                    tree_data[mod_name][race][size] = {}
                if not(mtype in tree_data[mod_name][race][size]):
                    tree_data[mod_name][race][size][mtype] = {}

                item_data = {'mod':mod, 'race':race, 'obj':module_obj}
                tree_data[mod_name][race][size][mtype][module_obj.get_internal_name()] = (module_obj.get_name(), item_data)
    

    def refresh_tree(self):
        tree_data = {}
        
        if self.show_all:
            for mod in self.gsbi.get_mod_list_friendly():
                self.generate_tree_data(tree_data, self.gsbi.get_mod_by_friendly_name(mod))
        else:
            self.generate_tree_data(tree_data, self.gsbi.get_current_mod())
        
        self.update_tree_data(tree_data)


    def update_tree_data(self, tree_data):
        self.updating_tree_data = True
        
        self.module_tree.DeleteAllItems()
        root = self.module_tree.AddRoot('DUMMY')
        
        name_match = None
        internal_name_match = None
        
        mtype_order = ['Weapons', 'Defenses', 'Engines', 'Other']
        
        for mod in sorted(tree_data.keys()):
            races = tree_data[mod]
            
            if self.show_all:
                this_mod = self.module_tree.AppendItem(root, mod)
            else:
                this_mod = root

            race_list = sorted(races.keys())
            if 'Generic' in race_list:
                race_list.remove('Generic')
                race_list.insert(0, 'Generic')
            for race in race_list:
                sizes = races[race]
                
                this_race = self.module_tree.AppendItem(this_mod, race)
                
                for size in sorted(sizes.keys()):
                    mtypes = sizes[size]
                    
                    this_size = self.module_tree.AppendItem(this_race, size)
                    
                    for mtype in mtype_order:
                        if not(mtype in mtypes): continue
                        modules = mtypes[mtype]

                        this_mtype = self.module_tree.AppendItem(this_size, mtype)
                        
                        for module in sorted(modules.keys()):
                            module_name,module_data = modules[module]
                            item_data = wx.TreeItemData(module_data)
                            module_obj = module_data['obj']
                           
                            this_module = self.module_tree.AppendItem(this_mtype, module_name, data=item_data)
                            
                            if self.module_data:
                                if self.module_data.get_name() == module_obj.get_name():
                                    name_match = this_module
                                if self.module_data.get_internal_name() == module_obj.get_internal_name():
                                    internal_name_match = this_module

        self.updating_tree_data = False

        if internal_name_match:
            self.expand_parents(internal_name_match)
            self.select_item(internal_name_match)
        elif name_match:
            self.expand_parents(name_match)
            self.select_item(name_match)
    
    
    def select_item(self, item):
        self.module_tree.SelectItem(item)


    def expand_parents(self, leaf_node):
        this_node = leaf_node
        self.module_tree.Expand(this_node)
        this_node = self.module_tree.GetItemParent(this_node)
        while this_node and self.module_tree.IsVisible(this_node):
            self.module_tree.Expand(this_node)
            this_node = self.module_tree.GetItemParent(this_node)


    def update_show_all(self, event):
        # Update our flag and then refresh the tree.
        self.show_all = event.Checked()
        self.refresh_tree()
    

    def new_gsbi(self, gsbi):
        # Store the new GSBInstall object and then refresh the tree.
        self.gsbi = gsbi
        self.refresh_tree()
    
    
    def get_leaf_from_name(self, parent, name):
        item, cookie = self.module_tree.GetFirstChild(parent)
        while item:
            if self.module_tree.ItemHasChildren(item):
                leaf = self.get_leaf_from_name(item, name)
                if leaf != None: return leaf
            else:
                data = self.module_tree.GetItemData(item).GetData()
                if data['obj'].get_internal_name() == name:
                    return item
            item, cookie = self.module_tree.GetNextChild(parent, cookie)
        return None
    
    
    def get_leaf_from_module(self, module):
        root = self.module_tree.GetRootItem()
        name = module.get_internal_name()
        
        leaf = self.get_leaf_from_name(root, name)
        if leaf == None: return None
        return leaf
        

    def edit_module(self, event):
        if self.updating_tree_data: return
        
        # Store the data belonging to the selected module, and then call
        # the callback.
        module_data = self.module_tree.GetItemData(event.GetItem()).GetData()
        if module_data == None: return

        self.double_select_callback(module_data['mod'], module_data['obj'])
        self.module_data = module_data['obj']


    def select_module(self, event):
        if self.updating_tree_data: return
        
        # Store the data belonging to the selected module, and then call
        # the callback.
        module_data = copy.copy(self.module_tree.GetItemData(event.GetItem()).GetData())
        if module_data == None:
            self.select_callback(None, None)
            return
        
        self.select_callback(module_data['mod'], module_data['obj'])
        self.module_data = module_data['obj']
    
